package NWPackage;

import java.util.List;
import java.util.Random;

import NW_MC.Huristics;
import NW_MC.MCEntropyMatrix;
import NW_MC.RandomMatrix;
import Readers.InputsReader;

public class MyThread implements Runnable {
	  String name; // name of thread

	  public Thread t;
	  public double weight = 0.0;
	  private ProbabilitiesMatrix normalizeProbabilityMatrix;
	  private PairPreferdCandidateCell CellAssumption;
	  private List<String> optionalWinners;
	  private double fullEntropy;
	  Random rand;  
	  Random rand2;
	  
	  public MyThread(String threadname, ProbabilitiesMatrix bigNormalizeProbabilityMatrix, 
			  PairPreferdCandidateCell bigCellAssumption, List<String> optionalWinners, double fullEntropy, int seed)throws Exception {
	    name = threadname;
	    normalizeProbabilityMatrix = bigNormalizeProbabilityMatrix;
	    CellAssumption = bigCellAssumption;
	    this.optionalWinners = optionalWinners;
	    this.fullEntropy = fullEntropy;
	    rand = new Random (seed);
	    rand2 = new Random(seed + 2);
	    t = new Thread(this, name);
	    //System.out.println("New thread: " + t);
	    t.start();
	  }

	  public void run() {
	    try {
			weight = CalcAssumptionEntropy();
		} catch (Exception e) {
			// TODO Auto-generated catch block			
			e.printStackTrace();	
			System.out.println("failed");						
		}
	    
	    //System.out.println(name + " exiting.");
	  
	  }

	private double CalcAssumptionEntropy() throws Exception {
		MCEntropyMatrix winnersStatistics = new MCEntropyMatrix(optionalWinners);
		//System.out.println("I'm here, calculating");	
		//Run X times The Random Number's Winner Process:
		for (int j = 0; j < InputsReader.getMonteCarloRandomProcess(); j++) {
			String candidateWinner="";
			try{
				candidateWinner = findRandomCandidateWinner(normalizeProbabilityMatrix,optionalWinners);
			}
			catch(Exception ex){
				//MsgLog.write("problem " +ex.getMessage());
				//ex.printStackTrace();
				throw new Exception ("ERROR in MYThread/calc assumption entropy");
			}
			//after each iteration save the winning to the Statistics:
			try {
				winnersStatistics.increaseCandidateWinner(candidateWinner);
			} 
			catch (Exception e) {
				//MsgLog.write("cannot increase the Candidate: " + candidateWinner );
				//e.printStackTrace();
				throw new Exception ("ERROR in MYThread/calc assumption entropy");
			}
		}
	//	System.out.println("still I'm here, calculating");
		//after all the X-MC iterations - calc the entropy of each Candidate:
		double assumptionProbability;
		//if assumption is NULL then we are calculating the full real Entropy
		if (this.CellAssumption == null)
			assumptionProbability = 1.0;
		//else we are calculating some query's Entropy
		else
			assumptionProbability = normalizeProbabilityMatrix.getAgentTotalProbability(this.CellAssumption.getAgentName());
		
		//return entropy for this query by huristics:
		switch(InputsReader.getHuristic())
		{
			case 1: 
				// only winners entropies
				return Huristics.AllWinners(this.CellAssumption, winnersStatistics, assumptionProbability, fullEntropy);
			case 2:
				//winner & Loser
				return Huristics.WinnerVSLoser(this.CellAssumption, winnersStatistics, assumptionProbability, fullEntropy);
			case 3:
				//winner & second-winner
				return Huristics.WinnerVSSecond(this.CellAssumption, winnersStatistics, assumptionProbability, fullEntropy);
			case 6:
				//myopic
				return Huristics.Myopic(this.CellAssumption, winnersStatistics, assumptionProbability);
			case 7:
				//myopic winner
				return Huristics.MyopicWinner(this.CellAssumption, winnersStatistics, assumptionProbability);
			case 8:
				//pure winner
				return Huristics.PureWinner(this.CellAssumption, winnersStatistics, assumptionProbability);
			case 9:
				//pure preferred winner
				return Huristics.PurePreferredWinner(this.CellAssumption, winnersStatistics, assumptionProbability);
			default:
				//all queries - Entropy Only
				return Huristics.allQueries(winnersStatistics, assumptionProbability, fullEntropy);
		}

	}

	private String findRandomCandidateWinner(
			ProbabilitiesMatrix probMatrix,
			List<String> optionalWinners2) {
		RandomMatrix rMatrix = new RandomMatrix(optionalWinners);
		
		/*//FOR DEBUG ONLY
		double randomProb1 = 0.1;
		double randomProb2 = 0.2;
		ProbabilityCell probability1 = probMatrix.getProbability("V1",randomProb1);
		rMatrix.setCell(probability1);
		ProbabilityCell probability2 = probMatrix.getProbability("V2",randomProb2);
		rMatrix.setCell(probability2);
		*/
		
		//for each agent, get random Vote:
		String[] agents = InputsReader.getAgents();
		for (String  agent : agents) {
			double randomProb =rand.nextDouble(); // V1 = 0.2157 V2 = 0.6027 V3 = 0.4427
			ProbabilityCell probability = new ProbabilityCell();
			try{
				probability = probMatrix.getProbability(agent,randomProb);
				if (probability != null)
				{
					//save the vote in the randomMatrix
					rMatrix.setCell(probability);
				}
				else //agent have probability = 0 for this query
				{
					//MsgLog.write("error in prob matrix - agent " + agent + "not found or have 0 probability");
					//System.out.println("error in prob matrix - agent " + agent + "not found or have 0 probability");
				}
			}
			catch (Exception e) {
				//MsgLog.write("error in prob matrix - agent " + agent + "not found");
				//System.out.println("error in prob matrix - agent " + agent + "not found");
			}
		}
		
		//get the candidate with max value
		List<String> winnerList =  rMatrix.getWinnerCandidate();
		int idx = rand2.nextInt(winnerList.size());
		String winner = winnerList.get(idx);		 
		return winner;
	} 
	  
}


